package github.ziwukun.jsonql.lang;

import static github.ziwukun.jsonql.lang.CmpOpr.*;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;

import cn.hutool.core.util.StrUtil;

public class WhereBuilder implements Serializable{
	private static final long serialVersionUID = -291602575697501410L;
	
	String key;
	Serializable val;
	WhereBuilder(String key,Serializable val){
		this.key = key;
		this.val = val;
	}
	
	/**
	 * 等于搜索
	 * @param prop
	 * @param value
	 * @return
	 */
	public WhereBuilder eq(String prop,Serializable val) {
		setValue(createPropAndCompareAndValue(prop, EQ, val));
		return this;
	}
	
	/**
	 * 等于搜索
	 * @param prop
	 * @param value
	 * @return
	 */
	public WhereBuilder eq(boolean condition,String prop,Serializable val) {
		if(condition) {
			setValue(createPropAndCompareAndValue(prop, EQ, val));
		}
		return this;
	}
	
	/**
	 * 不等于搜索
	 * @return
	 */
	public WhereBuilder neq(String prop,Serializable val) {
		setValue(createPropAndCompareAndValue(prop, NEQ, val));
		return this;
	}
	
	/**
	 * 不等于搜索
	 * @return
	 */
	public WhereBuilder neq(boolean condition,String prop,Serializable val) {
		if(condition) {
			setValue(createPropAndCompareAndValue(prop, NEQ, val));
		}
		return this;
	} 
	
	/**
	 * 大于
	 * @return
	 */
	public WhereBuilder gt(String prop,Serializable val) {
		setValue(createPropAndCompareAndValue(prop, GT, val));
		return this;
	}
	
	/**
	 * 大于
	 * @return
	 */
	public WhereBuilder gt(boolean condition,String prop,Serializable val) {
		if(condition) {
			setValue(createPropAndCompareAndValue(prop, GT, val));
		}
		return this;
	}
	
	/**
	 * 小于
	 * @param prop
	 * @param value
	 * @return
	 */
	public WhereBuilder lt(String prop,Serializable val) {
		setValue(createPropAndCompareAndValue(prop, LT, val));
		return this;
	}
	
	/**
	 * 小于
	 * @param prop
	 * @param value
	 * @return
	 */
	public WhereBuilder lt(boolean condition,String prop,Serializable val) {
		if(condition) {
			setValue(createPropAndCompareAndValue(prop, LT, val));
		}
		return this;
	}
	
	/**
	 * 大于等于
	 * @return
	 */
	public WhereBuilder gte(String prop,Serializable val) {
		setValue(createPropAndCompareAndValue(prop, GTE, val));
		return this;
	}
	
	/**
	 * 大于等于
	 * @return
	 */
	public WhereBuilder gte(boolean condition,String prop,Serializable val) {
		if(condition) {
			setValue(createPropAndCompareAndValue(prop, GTE, val));
		}
		return this;
	}
	
	/**
	 * 小于等于
	 * @return
	 */
	public WhereBuilder lte(String prop,Serializable val) {
		setValue(createPropAndCompareAndValue(prop, LTE, val));
		return this;
	}
	
	/**
	 * 小于等于
	 * @return
	 */
	public WhereBuilder lte(boolean condition,String prop,Serializable val) {
		if(condition) {
			setValue(createPropAndCompareAndValue(prop, LTE, val));
		}
		return this;
	}
	
	/**
	 * In查询
	 * @param prop
	 * @param list
	 * @return
	 */
	public WhereBuilder in(String prop,List<?> list) {
		setValue(createPropAndCompareAndValue(prop, IN, new ArrayList<>(list)));
		return this;
	}
	
	/**
	 * In查询
	 * @param prop
	 * @param list
	 * @return
	 */
	public WhereBuilder in(boolean condition,String prop,List<?> list) {
		if(condition) {
			setValue(createPropAndCompareAndValue(prop, IN, new ArrayList<>(list)));
		}
		return this;
	}
	
	/**
	 * Not In查询
	 * @param prop
	 * @param list
	 * @return
	 */
	public WhereBuilder nin(String prop,List<?> list) {
		setValue(createPropAndCompareAndValue(prop, NIN, new ArrayList<>(list)));
		return this;
	}
	
	/**
	 * Not In查询
	 * @param prop
	 * @param list
	 * @return
	 */
	public WhereBuilder nin(boolean condition,String prop,List<?> list) {
		if(condition) {
			setValue(createPropAndCompareAndValue(prop, NIN, new ArrayList<>(list)));
		}
		return this;
	}
	
	/**
	 * IS NULL查询
	 * @param prop
	 * @param list
	 * @return
	 */
	public WhereBuilder isNull(String prop) {
		setValue(createPropAndCompareAndValue(prop, ISNULL, true));
		return this;
	}
	
	/**
	 * IS NULL查询
	 * @param prop
	 * @param list
	 * @return
	 */
	public WhereBuilder isNull(boolean condition,String prop) {
		if(condition) {
			setValue(createPropAndCompareAndValue(prop, ISNULL, true));
		}
		return this;
	}
	
	/**
	 * NOT NULL查询
	 * @param prop
	 * @param list
	 * @return
	 */
	public WhereBuilder notNull(String prop) {
		setValue(createPropAndCompareAndValue(prop, NOTNULL, true));
		return this;
	}
	
	/**
	 * NOT NULL查询
	 * @param prop
	 * @param list
	 * @return
	 */
	public WhereBuilder notNull(boolean condition,String prop) {
		if(condition) {
			setValue(createPropAndCompareAndValue(prop, NOTNULL, true));
		}
		return this;
	}
	
	/**
	 * or
	 * @return
	 */
	public WhereBuilder or(Consumer<WhereBuilder> consumer) {
		WhereBuilder or = new WhereBuilder(OR.atWord(),new LinkedList<>());
		consumer.accept(or);
		setValue(or);
		return this;
	}
	
	/**
	 * or
	 * @return
	 */
	public WhereBuilder or(boolean condition,Consumer<WhereBuilder> consumer) {
		if(condition) {
			or(consumer);
		}
		return this;
	}
	
	/**
	 * and
	 * @param consumer
	 * @return
	 */
	public WhereBuilder and(Consumer<WhereBuilder> consumer) {
		WhereBuilder and = new WhereBuilder(AND.atWord(),new LinkedList<>());
		consumer.accept(and);
		setValue(and);
		return this;
	}
	
	/**
	 * and
	 * @param consumer
	 * @return
	 */
	public WhereBuilder and(boolean condition,Consumer<WhereBuilder> consumer) {
		if(condition) {
			and(consumer);
		}
		return this;
	}
	
	/**
	 * 添加子属性的搜索条件
	 * @param prop
	 * @param consumer
	 * @return
	 */
	public WhereBuilder prop(String prop,Consumer<WhereBuilder> consumer) {
		WhereBuilder consumerBuilder = new WhereBuilder(null,null);
		consumer.accept(consumerBuilder);
		
		WhereBuilder propBuilder = new WhereBuilder(prop,consumerBuilder);
		setValue(propBuilder);
		return this;
	}
	
	/**
	 * 添加子属性的搜索条件
	 * @param prop
	 * @param consumer
	 * @return
	 */
	public WhereBuilder prop(boolean condition,String prop,Consumer<WhereBuilder> consumer) {
		if(condition) {
			prop(prop, consumer);
		}
		return this;
	}
	
	private void setValue(WhereBuilder builder) {
		// 如果自己本身就没有值就复制builder的值到自己内部
		if(StrUtil.isBlank(this.key)) {
			this.key = builder.key;
			this.val = builder.val;
			return;
		}
		// 如果是and或or条件，将值设置到列表中
		else if(AND.atWord().equals(this.key) || OR.atWord().equals(this.key)) {
			@SuppressWarnings("unchecked")
			List<WhereBuilder> conditions = (List<WhereBuilder>) val;
			conditions.add(builder);
			return;
		}
		// key是一般属性，这时又设置了新的属性
		// 自己变成and,将多个属性用and链接
		else if(!isCmpOpr(this.key) && !this.key.contains("@")) {
			LinkedList<WhereBuilder> andConditions = new LinkedList<WhereBuilder>();
			andConditions.add(new WhereBuilder(this.key,this.val));
			andConditions.add(builder);
			
			this.key = AND.atWord();
			this.val = andConditions;
			return;
		}
		else {
			throw new JSONQLBuildException("未知的WhereBuilder状态\n"
				+ "this=====>{}", this.toString());
		}
	}
	
	private WhereBuilder createPropAndCompareAndValue(String prop,CmpOpr compare,Serializable val) {
		if(StrUtil.isBlankIfStr(prop)) {
			throw new JSONQLBuildException("属性名不能为空字符串");
		}
		if(prop.contains("@")) {
			throw new JSONQLBuildException("属性名{}不能为包含@符号",prop);
		}
		if(val != null && !compare.support(val)) {
			throw new JSONQLBuildException("比较符{}不支持对象值{}",compare.atWord(),val.toString());
		}
		return new WhereBuilder(prop, new WhereBuilder(compare.atWord(), val));
	}
	
	public Where build() {
		// 如果Builder是无效的
		if(this.key == null) {
			return null;
		}
		
		// AND | OR 逻辑符号
		else if(AND.atWord().equals(this.key) || OR.atWord().equals(this.key)) {
			LinkedList<Where> wheres = new LinkedList<>();
			@SuppressWarnings("unchecked")
			List<WhereBuilder> whereBuilders = (List<WhereBuilder>) this.val;
			for (WhereBuilder whereBuilder : whereBuilders) {
				if(whereBuilder.shouldBuild()) {
					wheres.add(whereBuilder.build());
				}
			}
			
			return new WhereImpl(key, wheres);
		}
		// 其他普通比较符
		else if(isCmpOpr(this.key)) {
			return new WhereImpl(key,val);
		}
		// 普通属性
		else if(!isCmpOpr(this.key) && !this.key.contains("@")) {
			if(this.shouldBuild()) {
				return new WhereImpl(key,((WhereBuilder)val).build());
			}
		}
		throw new JSONQLBuildException("未知的JsonQLWhereBuilder状态\n"
			+ "builder=====>{}", this.toString());
	}
	
	/**
	 * 是否需要build
	 * @return
	 */
	boolean shouldBuild() {
		// 自己本身没有设置有意义的值，不需要build
		if(StrUtil.isBlank(this.key)) {
			return false;
		}
		
		// 如果自己的key表示的是属性，就检查一下自己的下级是否需要build
		if(!isCmpOpr(this.key)) {
			if(this.val == null || !(this.val instanceof WhereBuilder)) {
				return false;
			}
			WhereBuilder valueBuilder = (WhereBuilder)this.val;
			return valueBuilder.shouldBuild();
		}
		return true;
	}
	
	/**
	 * 获取集合中属性类型为JsonQLWhere，最大的深度
	 * @param collection
	 * @return
	 */
	static int getMaxDeep(Collection<?> collection) {
		int maxDeep = 1;
		for(Object subValue:collection) {
			if(subValue instanceof Where) {
				int deep = ((Where)subValue).deep() + 1;
				if(maxDeep < deep) {
					maxDeep = deep;
				}
			}
		}
		return maxDeep;
	}
}
